#include "csharp_generator.h"
#include "pp_utils.h"
#include "pp_generator.h"

#include <iostream>
#include <sstream>
#include <map>
#include <algorithm>

#define PP_GEN_CSHARP_VERSION "1.0.1"

#define JSON_TYPE_NONE      "none"
#define JSON_TYPE_UNITY     "unity"
//#define JSON_TYPE_NATIVE    "native"
//#define JSON_TYPE_NEWTON    "newtonsoft"

namespace pp
{
    const std::map<std::string, std::string> TYPES_MAP = {
        {"uint8", "byte"}, {"int8", "sbyte"},
        {"uint16", "ushort"}, {"int16", "short"},
        {"uint32", "uint"}, {"int32", "int"},
        {"uint64", "ulong"}, {"int64", "long"},
        {"float32", "float"}, {"float64", "double"},
        {"float", "float"}, {"double", "double"},
        {"string", "string"},
    };

    void CSharpGenerator::Reset(const std::string& srcfile)
    {
        CodeGenerator::Reset(srcfile);
        m_sNameSpace = "";
    }

    void CSharpGenerator::HandleImport(const std::string& imports)
    {
        std::string srcfile = m_sSrcDir + "/" + imports;
        std::shared_ptr<CSharpGenerator> csGen = std::make_shared<CSharpGenerator>(m_sSrcDir, m_sOutDir);
        std::shared_ptr<CodeGenerator> gen = csGen;
        std::shared_ptr<CodeHandler> hdr = std::make_shared<CodeHandler>(gen);
        Parser parser;
        csGen->Reset(srcfile);
        parser.SetHandler(hdr);
        parser.ParseFile(srcfile);
        m_oImports.push_back(csGen->GetNameSpace());
        // 常量映射
        for (auto& iter : csGen->GetConstMap())
        {
            m_oConstMap[csGen->GetPackage() + "." + iter.first] = iter.second;
        }
        // 枚举
        for (auto& v : csGen->GetEnums())
        {
            m_oEnumList.insert(csGen->GetPackage() + "." + v->GetName());
        }
    }

    void CSharpGenerator::HandleOption(const std::string& name, const std::string& value)
    {
        if (name == "cs_package" || name == "csharp_package")
        {
            m_sNameSpace = value;
        }
        else if (name == "cs_json" || name == "csharp_json")
        {
            m_sJsonType = value;
        }
    }

    void CSharpGenerator::HandleConst(const std::shared_ptr<FieldInfo>& fieldInfo)
    {
        CodeGenerator::HandleConst(fieldInfo);
        // 常量缓存
        m_oConstMap[fieldInfo->GetName()] = GetNameSpace() + "." + GetConstFile() + "Constants." + fieldInfo->GetName();
    }

    // 处理pp文件中的enum定义
    void CSharpGenerator::HandleEnum(const std::shared_ptr<StructInfo>& structInfo)
    {
        CodeGenerator::HandleEnum(structInfo);
        // 常量缓存
        for (auto& v : structInfo->GetFields())
        {
            m_oConstMap[v->GetName()] = GetNameSpace() + "." + structInfo->GetName() + "." + v->GetName();
        }
        // 枚举缓存
        m_oEnumList.insert(structInfo->GetName());
    }

    // 处理pp文件中的message定义
    void CSharpGenerator::HandleStruct(const std::shared_ptr<StructInfo>& structInfo)
    {
        CodeGenerator::HandleStruct(structInfo);
        m_oConstMap[structInfo->GetName()] = GetNameSpace() + "." + ToPascalCase(structInfo->GetName());
    }

    void CSharpGenerator::Generate()
    {
        std::string relpath = GetRelativePath(m_sSrcDir, m_sSrcFile) + Replace(GetNameSpace(), ".", "/");
        std::string outpath = m_sOutDir + "/" + relpath + "/";

        try
        {
            CreateDirectories(outpath);
            // 宏定义单独使用一个文件
            GenerateConstFile(outpath);
            // 为struct生成cs文件
            GenerateClassFile(outpath);
        }
        catch (const std::exception& e)
        {
            std::cerr << M_ERR_COLOR_START "error: source code for file '" << m_sSrcFile << "' fail:"
                << e.what() << M_ERR_COLOR_END << std::endl;
        }
    }

    // 宏定义和枚举，独立一个文件
    void CSharpGenerator::GenerateConstFile(const std::string& outdir)
    {
        // 先看看是否需要const文件
        if (m_oConsts.empty() && m_oEnums.empty()) return;

        std::string constname = GetConstFile();
        std::string constfile = outdir + constname + "Constants.cs";
        std::cout << "    --> " << constfile << std::endl;

        // 打开文件
        std::ofstream ofs(constfile, std::ios::out | std::ios::trunc);

        if (!ofs.is_open())
        {
            std::cerr << M_ERR_COLOR_START << "error: fail to open file '" << constfile
                << "' to write" << M_ERR_COLOR_END << std::endl;
            return;
        }

        ofs << "// Code generated by pp_gen_csharp. DO NOT EDIT." << std::endl
            << "// versions:" << std::endl
            << "//     pp_gen_csharp " PP_GEN_CSHARP_VERSION << std::endl
            << "//     pp_gen        " PP_GEN_VERSION << std::endl
            << "// source: " << TrimPath(m_sSrcFile) << std::endl << std::endl;

        GenerateNamespace(ofs);
        if (!m_oConsts.empty()) GenerateConst(ofs, constname);
        if (!m_oConsts.empty()) GenerateEnum(ofs);

        // 文件结尾
        if (!GetNameSpace().empty()) ofs << "}" << std::endl;

        ofs.close();
    }

    // 头文件宏定义
    void CSharpGenerator::GenerateConst(std::ofstream& ofs, const std::string& constname)
    {
        std::string nsi = GetNameSpaceIndentation();
        std::vector<std::string> clist;
        uint32_t maxlen = 0;

        ofs << nsi << "public static class " << constname << "Constants" << std::endl
            << nsi << "{" << std::endl;

        // 以下逻辑的目的，先算出const的最大长度，目的是为了对齐注释
        for (auto& v: m_oConsts)
        {
            std::string qoutes = v->GetType() == "string" ? "\"" : "";
            std::stringstream ss;
            ss << nsi << CODE_INDENTATION << "public const " << GetClassType(v->GetType()) << " "
                << v->GetName() << " = " << qoutes << v->GetValue() << qoutes << ";";
            std::string sval = ss.str();
            if (sval.length() > maxlen) maxlen = sval.length();
            clist.push_back(sval);
        }

        // 对齐注释，输出到文件
        for (size_t i = 0; i < clist.size(); i++)
        {
            auto v = m_oConsts[i];
            std::string sval = clist[i];

            ofs << sval;
            if (!v->GetDesc().empty())
            {
                for (size_t j = 0; j < maxlen - sval.size(); j++) ofs << " ";
                ofs << "    // " << v->GetDesc();
            }
            ofs << std::endl;
        }

        ofs << nsi << "}" << std::endl;
        if (!m_oEnums.empty()) ofs << std::endl;
    }

    // 头文件枚举定义
    void CSharpGenerator::GenerateEnum(std::ofstream& ofs)
    {
        std::string nsi = GetNameSpaceIndentation();
        int i = 0;

        for (auto& v : m_oEnums)
        {
            if (i > 0) ofs << std::endl;

            if (!v->GetDesc().empty()) ofs << nsi << "// " << v->GetDesc() << std::endl;
            ofs << nsi << "public enum " << v->GetName() << std::endl
                << nsi << "{" << std::endl;
            GenerateEnumValues(ofs, v->GetName(), v->GetFields());
            ofs << nsi << "}" << std::endl;
            i++;
        }
    }

    // 头文件枚举值
    void CSharpGenerator::GenerateEnumValues(std::ofstream& ofs, const std::string& enumName, const std::vector<std::shared_ptr<FieldInfo> >& vals)
    {
        std::string nsi = GetNameSpaceIndentation();
        std::vector<std::string> clist;
        uint32_t maxlen = 0;

        // 以下逻辑的目的，先算出最大长度，目的是为了对齐注释
        for (auto& v: vals)
        {
            std::stringstream ss;
            ss << nsi << CODE_INDENTATION << v->GetName() << " = " << v->GetValue() << ",";
            std::string sval = ss.str();
            if (sval.length() > maxlen) maxlen = sval.length();
            clist.push_back(sval);
        }

        // 对齐注释，输出到文件
        for (size_t i = 0; i < clist.size(); i++)
        {
            auto v = vals[i];
            std::string sval = clist[i];

            ofs << sval;
            if (!v->GetDesc().empty())
            {
                for (size_t j = 0; j < maxlen - sval.size(); j++) ofs << " ";
                ofs << "    // " << v->GetDesc();
            }
            ofs << std::endl;
        }
    }

    // 生成class文件，每个message一个文件
    void CSharpGenerator::GenerateClassFile(const std::string& outdir)
    {
        std::string nsi = GetNameSpaceIndentation();

        for (auto& v: m_oStructs)
        {
            std::string className = ToPascalCase(v->GetName());
            std::string classFile = outdir + className + ".cs";
            std::cout << "    --> " << classFile << std::endl;

            // 打开文件
            std::ofstream ofs(classFile, std::ios::out | std::ios::trunc);

            if (!ofs.is_open())
            {
                std::cerr << M_ERR_COLOR_START << "error: fail to open file '" << classFile
                    << "' to write" << M_ERR_COLOR_END << std::endl;
                return;
            }

            ofs << "// Code generated by pp_gen_csharp. DO NOT EDIT." << std::endl
                << "// versions:" << std::endl
                << "//     pp_gen_csharp " PP_GEN_CSHARP_VERSION << std::endl
                << "//     pp_gen        " PP_GEN_VERSION << std::endl
                << "// source: " << TrimPath(m_sSrcFile) << "#" << v->GetName() << std::endl << std::endl;

            GenerateImports(ofs);
            GenerateNamespace(ofs);

            ofs << nsi << "#nullable enable" << std::endl
                << nsi << "[Serializable]" << std::endl
                << nsi << "public class " << className << " : ProtoPack.Message" << std::endl
                << nsi << "{" << std::endl;

            GenerateClassAttributes(ofs, v->GetFields());
            GenerateClassConstructor(ofs, className, v->GetFields());

            // 编码函数
            ofs << nsi << CODE_INDENTATION << "public override void Encode(ProtoPack.ByteArray buf, ulong tag)" << std::endl
                << nsi << CODE_INDENTATION << "{" << std::endl;
            GenerateClassEncodeFunction(ofs, v->GetFields());
            ofs << nsi << CODE_INDENTATION << "}" << std::endl << std::endl;

            // 解码函数
            ofs << nsi << CODE_INDENTATION << "protected override int DecodeSubField(ulong tag, byte[] bytes, uint start, uint len)" << std::endl
                << nsi << CODE_INDENTATION << "{" << std::endl;
            GenerateClassDecodeFunction(ofs, v->GetFields());
            ofs << nsi << CODE_INDENTATION << CODE_INDENTATION << "return 0;" << std::endl
                << nsi << CODE_INDENTATION << "}" << std::endl << std::endl;

            // ToJson
            ofs << nsi << CODE_INDENTATION << "public override string ToJson()" << std::endl
                << nsi << CODE_INDENTATION << "{" << std::endl;
            GenerateClassToJsonFunction(ofs, v->GetFields());
            ofs << nsi << DOUBLE_CODE_INDENTATION << "return \"{\" + sb.ToString().TrimEnd(',') + \"}\";" << std::endl
                << nsi << CODE_INDENTATION << "}" << std::endl << std::endl;

            // ToString
            ofs << nsi << CODE_INDENTATION << "public override string ToString()" << std::endl
                << nsi << CODE_INDENTATION << "{" << std::endl;
            GenerateClassToStringFunction(ofs, v->GetFields());
            ofs << nsi << DOUBLE_CODE_INDENTATION << "return \"{\" + sb.ToString().TrimEnd(',') + \"}\";" << std::endl
                << nsi << CODE_INDENTATION << "}" << std::endl;

            // From Json
            if (m_sJsonType == JSON_TYPE_UNITY)
            {
                ofs << std::endl
                    << nsi << CODE_INDENTATION << "public void FromJson(" << className << "Json jval)" << std::endl
                    << nsi << CODE_INDENTATION << "{" << std::endl;
                GenerateClassFromJsonFunction(ofs, v->GetFields());
                ofs << nsi << CODE_INDENTATION << "}" << std::endl;
            }

            // 类结束
            ofs << nsi << "}" << std::endl;

            if (m_sJsonType == JSON_TYPE_UNITY)
            {
                ofs << std::endl
                    << nsi << "[Serializable]" << std::endl
                    << nsi << "public class " << className << "Json" << std::endl
                    << nsi << "{" << std::endl;
                GenerateJsonClassAttributes(ofs, v->GetFields());
                GenerateJsonClassConstructor(ofs, className, v->GetFields());
                ofs << nsi << "}" << std::endl;
            }

            ofs << nsi << "#nullable disable" << std::endl;

            // 文件结尾
            if (!GetNameSpace().empty()) ofs << "}" << std::endl;

            ofs.close();
        }
    }

    // 生成using
    void CSharpGenerator::GenerateImports(std::ofstream& ofs)
    {
        ofs << "using System;" << std::endl;                        // unity [Serializable]需要这项
        ofs << "using System.Collections.Generic;" << std::endl;    // unity list需要这项
        ofs << "using System.Text;" << std::endl;

        for (auto& v : m_oImports)
        {
            ofs << "using " << v << ";" << std::endl;
        }

        ofs << std::endl;
    }

    // 消息成员定义
    void CSharpGenerator::GenerateClassAttributes(std::ofstream& ofs, const std::vector<std::shared_ptr<FieldInfo> >& vals)
    {
        if (vals.empty()) return;

        std::string nsi = GetNameSpaceIndentation();

        for (auto& v: vals)
        {
            // 注释
            if (!v->GetDesc().empty())
            {
                ofs << nsi << CODE_INDENTATION << "/// <summary>" << std::endl
                    << nsi << CODE_INDENTATION << "/// " << v->GetDesc() << std::endl
                    << nsi << CODE_INDENTATION << "/// </summary>" << std::endl;
            }
            std::string memberName = ToPascalCase(v->GetName());
            std::string priName = memberName; //"_" + ToLowerFirst(memberName);
            std::string obtainName = "Obtain" + ToPascalCase(v->GetName());
            // set, get (为了兼容unity，不使用set, get，直接将属性定义为public)
            ofs << nsi << CODE_INDENTATION << "public " << GetClassAttribute(v->GetType(), v->GetSubType(), priName)
                << ";" << std::endl << std::endl;
                //<< nsi << CODE_INDENTATION << "public " << GetClassAttribute(v->GetType(), v->GetSubType(), memberName)
                //<< " {get {return " << priName << ";} set {" << priName << " = value;}}" << std::endl << std::endl;
        }
    }

    // 构造函数
    void CSharpGenerator::GenerateClassConstructor(std::ofstream& ofs, const std::string& className,
        const std::vector<std::shared_ptr<FieldInfo> >& vals)
    {
        std::string nsi = GetNameSpaceIndentation();
        ofs << nsi << CODE_INDENTATION << "public " << className << "()" << std::endl
            << nsi << CODE_INDENTATION << "{" << std::endl;

        for (auto& v: vals)
        {
            std::string memberName = ToPascalCase(v->GetName());
            std::string priName = memberName;// "_" + ToLowerFirst(memberName);

            if (v->GetType() == "array")
            {
                ofs << nsi << CODE_INDENTATION << CODE_INDENTATION << priName <<
                    " = new();" << std::endl;
                continue;
            }

            auto iter = TYPES_MAP.find(v->GetType());
            if (iter == TYPES_MAP.end()) continue;

            if (v->GetType() == "string")
            {
                ofs << nsi << CODE_INDENTATION << CODE_INDENTATION << priName <<
                    " = " << GetImportValue(v->GetDefault(), true) << ";" << std::endl;
            }
            else if (!v->GetDefault().empty())
            {
                ofs << nsi << CODE_INDENTATION << CODE_INDENTATION << priName <<
                    " = " << GetImportValue(v->GetDefault(), false, iter->second, memberName) << ";" << std::endl;
            }
        }

        ofs << nsi << CODE_INDENTATION << "}" << std::endl << std::endl;
    }

    // 编码函数
    void CSharpGenerator::GenerateClassEncodeFunction(std::ofstream& ofs, const std::vector<std::shared_ptr<FieldInfo> >& vals)
    {
        if (vals.empty()) return;

        std::string nsi = GetNameSpaceIndentation();

        ofs << nsi << CODE_INDENTATION << CODE_INDENTATION << "// Encode sub field" << std::endl
            << nsi << CODE_INDENTATION << CODE_INDENTATION
            << "ProtoPack.ByteArray subBuf = new ProtoPack.ByteArray(128);" << std::endl;

        for (auto& v: vals)
        {
            std::string attrName = ToPascalCase(v->GetName());

            if (v->GetType() == "array")
            {
                auto iter = TYPES_MAP.find(v->GetSubType());
                if (iter != TYPES_MAP.end())
                {
                    ofs << nsi << CODE_INDENTATION << CODE_INDENTATION << "ArrayEncode(subBuf, "
                        << GetImportValue(v->GetTag()) << ", " << attrName << ");" << std::endl;
                }
                else
                {
                    //std::string ftype = ToPascalCase(v->GetSubType());
                    ofs << nsi << CODE_INDENTATION << CODE_INDENTATION << "ArrayEncode(subBuf, "
                        << GetImportValue(v->GetTag()) << ", " << attrName << ");" << std::endl;
                }
            }
            else
            {
                if (TYPES_MAP.find(v->GetType()) != TYPES_MAP.end() || m_oEnumList.find(v->GetType()) != m_oEnumList.end())
                {
                    ofs << nsi << CODE_INDENTATION << CODE_INDENTATION << "FieldEncode(subBuf, "
                        << GetImportValue(v->GetTag()) << ", " << attrName << ");" << std::endl;
                }
                else
                {
                    ofs << nsi << CODE_INDENTATION << CODE_INDENTATION << attrName << "?.Encode(subBuf, "
                        << GetImportValue(v->GetTag()) << ");" << std::endl;
                }
            }
        }

        ofs << nsi << CODE_INDENTATION << CODE_INDENTATION << "// Encode the entire field" << std::endl
            << nsi << CODE_INDENTATION << CODE_INDENTATION
            << "buf.AppendVarint(tag).AppendVarint((ulong)subBuf.Length()).Append(subBuf.GetAllocBytes(), 0, (int)subBuf.Length());" << std::endl;
   }

    // 解码函数
    void CSharpGenerator::GenerateClassDecodeFunction(std::ofstream& ofs, const std::vector<std::shared_ptr<FieldInfo> >& vals)
    {
        if (vals.empty()) return;

        std::string nsi = GetNameSpaceIndentation();
        ofs << nsi << DOUBLE_CODE_INDENTATION << "switch (tag)" << std::endl
            << nsi << DOUBLE_CODE_INDENTATION << "{" << std::endl;

        for (auto& v: vals)
        {
            std::string attrName = ToPascalCase(v->GetName());
            std::string priName = attrName;//"_" + ToLowerFirst(attrName);

            if (v->GetType() == "array")
            {
                auto iter = TYPES_MAP.find(v->GetSubType());
                if (iter != TYPES_MAP.end())
                {
                    std::string refLen = v->GetSubType() == "string" ? ", len" : "";
                    std::string valDef = v->GetSubType() == "string" ? "\"\"" : "0";
                    ofs << nsi << DOUBLE_CODE_INDENTATION << "case " << GetImportValue(v->GetTag()) << ":" << std::endl
                        << nsi << DOUBLE_CODE_INDENTATION << CODE_INDENTATION << "{" << std::endl
                        << nsi << DOUBLE_CODE_INDENTATION << CODE_INDENTATION << CODE_INDENTATION
                        << iter->second << " val = " << valDef << ";" << std::endl
                        << nsi << DOUBLE_CODE_INDENTATION << CODE_INDENTATION << CODE_INDENTATION
                        << "int iRet = FieldDecode(bytes, start" << refLen << ", ref val);" << std::endl
                        << nsi << DOUBLE_CODE_INDENTATION << CODE_INDENTATION << CODE_INDENTATION
                        << "if (iRet != 0) return iRet;" << std::endl
                        << nsi << DOUBLE_CODE_INDENTATION << CODE_INDENTATION << CODE_INDENTATION
                        << priName << ".Add(val);" << std::endl
                        << nsi << DOUBLE_CODE_INDENTATION << CODE_INDENTATION << "}" << std::endl
                        << nsi << DOUBLE_CODE_INDENTATION << CODE_INDENTATION << "break;" << std::endl;
                }
                else
                {
                    std::string ftype = GetImportValue(v->GetSubType(), false, "");
                    ofs << nsi << DOUBLE_CODE_INDENTATION << "case " << GetImportValue(v->GetTag()) << ":" << std::endl
                        << nsi << DOUBLE_CODE_INDENTATION << CODE_INDENTATION << "{" << std::endl
                        << nsi << DOUBLE_CODE_INDENTATION << CODE_INDENTATION << CODE_INDENTATION
                        << ftype << " val = new();" << std::endl
                        << nsi << DOUBLE_CODE_INDENTATION << CODE_INDENTATION << CODE_INDENTATION
                        << "int iRet = val.Decode(bytes, start, len, false);" << std::endl
                        << nsi << DOUBLE_CODE_INDENTATION << CODE_INDENTATION << CODE_INDENTATION
                        << "if (iRet != 0) return iRet;" << std::endl
                        << nsi << DOUBLE_CODE_INDENTATION << CODE_INDENTATION << CODE_INDENTATION << priName << ".Add(val);" << std::endl
                        << nsi << DOUBLE_CODE_INDENTATION << CODE_INDENTATION << "}" << std::endl
                        << nsi << DOUBLE_CODE_INDENTATION << CODE_INDENTATION << "break;" << std::endl;
                }
            }
            else
            {
                if (TYPES_MAP.find(v->GetType()) != TYPES_MAP.end() || m_oEnumList.find(v->GetType()) != m_oEnumList.end())
                {
                    std::string refLen = v->GetType() == "string" ? ", len" : "";
                    ofs << nsi << DOUBLE_CODE_INDENTATION << "case " << GetImportValue(v->GetTag()) << ":" << std::endl
                        << nsi << DOUBLE_CODE_INDENTATION << CODE_INDENTATION
                        << "return FieldDecode(bytes, start" << refLen << ", ref " << priName << ");" << std::endl;
                }
                else
                {
                    ofs << nsi << DOUBLE_CODE_INDENTATION << "case " << GetImportValue(v->GetTag()) << ":" << std::endl
                        << nsi << DOUBLE_CODE_INDENTATION << CODE_INDENTATION << priName << " \?\?= new();" << std::endl
                        << nsi << DOUBLE_CODE_INDENTATION << CODE_INDENTATION << "return " << priName
                        << ".Decode(bytes, start, len, false);" << std::endl;
                }
            }
        }

        ofs << nsi << DOUBLE_CODE_INDENTATION << "default:" << std::endl
            << nsi << DOUBLE_CODE_INDENTATION << CODE_INDENTATION << "break;" << std::endl
            << nsi << DOUBLE_CODE_INDENTATION << "}" << std::endl;
    }

    // ToJson函数
    void CSharpGenerator::GenerateClassToJsonFunction(std::ofstream& ofs, const std::vector<std::shared_ptr<FieldInfo> >& vals)
    {
        std::string nsi = GetNameSpaceIndentation();
        ofs << nsi << DOUBLE_CODE_INDENTATION << "StringBuilder sb = new();" << std::endl << std::endl;

        int i = 0;
        std::string sif;

        for (auto& v: vals)
        {
            std::string jsonName = v->GetJsonName().empty() ? v->GetName() : v->GetJsonName();
            std::string attrName = ToPascalCase(v->GetName());
            std::string priName = attrName;//"_" + ToLowerFirst(attrName);

            if (i > 0)
            {
                if (sif.empty())
                {
                    ofs << nsi << DOUBLE_CODE_INDENTATION << "sb.Append(" << "\',\');" << std::endl;
                }
                else
                {
                    ofs << ".Append(" << "\',\');" << std::endl;
                }
            }
            sif = "";
            i++;

            if (v->GetType() == "array")
            {
                ofs << nsi << DOUBLE_CODE_INDENTATION << "ArrayFieldToJson(sb, \"" << jsonName << "\", "
                    << priName << ");" << std::endl;
            }
            else
            {
                if (TYPES_MAP.find(v->GetType()) != TYPES_MAP.end() || m_oEnumList.find(v->GetType()) != m_oEnumList.end())
                {
                    ofs << nsi << DOUBLE_CODE_INDENTATION << "FieldToJson(sb, \"" << jsonName << "\", "
                        << priName << ");" << std::endl;
                }
                else
                {
                    sif = "if (" + priName + " != null) ";
                    ofs << nsi << DOUBLE_CODE_INDENTATION << sif << "sb.Append(\"\\\"" << jsonName << "\\\":\").Append(" << priName
                        << ".ToJson())";
                }
            }
        }

        if (!sif.empty()) ofs << ";" << std::endl;
    }

    // ToString函数
    void CSharpGenerator::GenerateClassToStringFunction(std::ofstream& ofs, const std::vector<std::shared_ptr<FieldInfo> >& vals)
    {
        std::string nsi = GetNameSpaceIndentation();
        ofs << nsi << DOUBLE_CODE_INDENTATION << "StringBuilder sb = new();" << std::endl << std::endl;

        int i = 0;
        std::string sif;

        for (auto& v: vals)
        {
            std::string jsonName = v->GetJsonName().empty() ? v->GetName() : v->GetJsonName();
            std::string attrName = ToPascalCase(v->GetName());
            std::string priName = attrName;//"_" + ToLowerFirst(attrName);

            if (i > 0)
            {
                if (sif.empty())
                {
                    ofs << nsi << DOUBLE_CODE_INDENTATION << "sb.Append(" << "\',\');" << std::endl;
                }
                else
                {
                    ofs << ".Append(" << "\',\');" << std::endl;
                }
            }
            sif = "";
            i++;

            if (v->GetType() == "array")
            {
                ofs << nsi << DOUBLE_CODE_INDENTATION << "ArrayFieldToString(sb, \"" << jsonName << "\", "
                    << priName << ");" << std::endl;
            }
            else
            {
                if (TYPES_MAP.find(v->GetType()) != TYPES_MAP.end() || m_oEnumList.find(v->GetType()) != m_oEnumList.end())
                {
                    ofs << nsi << DOUBLE_CODE_INDENTATION << "FieldToString(sb, \"" << jsonName << "\", "
                        << priName << ");" << std::endl;
                }
                else
                {
                    sif = "if (" + priName + " != null) ";
                    ofs << nsi << DOUBLE_CODE_INDENTATION << sif << "sb.Append(\"" << jsonName << ":\").Append(" << priName
                        << ".ToString())";
                }
            }
        }

        if (!sif.empty()) ofs << ";" << std::endl;
    }

    // FromJson函数
    void CSharpGenerator::GenerateClassFromJsonFunction(std::ofstream& ofs, const std::vector<std::shared_ptr<FieldInfo> >& vals)
    {
        if (vals.empty()) return;

        std::string nsi = GetNameSpaceIndentation();

        for (auto& v: vals)
        {
            std::string attrName = ToPascalCase(v->GetName());
            std::string jsonName = v->GetJsonName().empty() ? v->GetName() : v->GetJsonName();

            if (v->GetType() == "array")
            {
                auto iter = TYPES_MAP.find(v->GetSubType());
                if (iter != TYPES_MAP.end())
                {
                    ofs << nsi << CODE_INDENTATION << CODE_INDENTATION << attrName << " = jval."
                        << jsonName << ";" << std::endl;
                }
                else
                {
                    std::string ftype = GetImportValue(v->GetSubType(), false, "");
                    ofs << nsi << CODE_INDENTATION << CODE_INDENTATION << "foreach (var jv in jval." << jsonName << ")" << std::endl
                        << nsi << CODE_INDENTATION << CODE_INDENTATION << "{" << std::endl
                        << nsi << DOUBLE_CODE_INDENTATION << CODE_INDENTATION << ftype << " val = new();" << std::endl
                        << nsi << DOUBLE_CODE_INDENTATION << CODE_INDENTATION << "val.FromJson(jv);" << std::endl
                        << nsi << DOUBLE_CODE_INDENTATION << CODE_INDENTATION << attrName << ".Add(val);" << std::endl
                        << nsi << CODE_INDENTATION << CODE_INDENTATION << "}" << std::endl;
                }
            }
            else
            {
                if (TYPES_MAP.find(v->GetType()) != TYPES_MAP.end() || m_oEnumList.find(v->GetType()) != m_oEnumList.end())
                {
                    ofs << nsi << CODE_INDENTATION << CODE_INDENTATION << attrName << " = jval."
                        << jsonName << ";" << std::endl;
                }
                else
                {
                    ofs << nsi << CODE_INDENTATION << CODE_INDENTATION << "if (jval." << jsonName << " != null)" << std::endl
                        << nsi << CODE_INDENTATION << CODE_INDENTATION << "{" << std::endl
                        << nsi << DOUBLE_CODE_INDENTATION << CODE_INDENTATION << attrName << " ??" << "= new();" << std::endl
                        << nsi << DOUBLE_CODE_INDENTATION << CODE_INDENTATION << attrName << ".FromJson(jval." << jsonName << ");" << std::endl
                        << nsi << CODE_INDENTATION << CODE_INDENTATION << "}" << std::endl;
                }
            }
        }
    }

    // 消息成员定义
    void CSharpGenerator::GenerateJsonClassAttributes(std::ofstream& ofs, const std::vector<std::shared_ptr<FieldInfo> >& vals)
    {
        if (vals.empty()) return;

        std::string nsi = GetNameSpaceIndentation();

        for (auto& v: vals)
        {
            // 注释
            if (!v->GetDesc().empty())
            {
                ofs << nsi << CODE_INDENTATION << "/// <summary>" << std::endl
                    << nsi << CODE_INDENTATION << "/// " << v->GetDesc() << std::endl
                    << nsi << CODE_INDENTATION << "/// </summary>" << std::endl;
            }
            std::string jsonName = v->GetJsonName().empty() ? v->GetName() : v->GetJsonName();
            ofs << nsi << CODE_INDENTATION << "public " << GetJsonClassAttribute(v->GetType(), v->GetSubType(), jsonName)
                << ";" << std::endl << std::endl;
        }
    }

    // 构造函数
    void CSharpGenerator::GenerateJsonClassConstructor(std::ofstream& ofs, const std::string& className,
        const std::vector<std::shared_ptr<FieldInfo> >& vals)
    {
        std::string nsi = GetNameSpaceIndentation();
        ofs << nsi << CODE_INDENTATION << "public " << className << "Json()" << std::endl
            << nsi << CODE_INDENTATION << "{" << std::endl;

        for (auto& v: vals)
        {
            std::string jsonName = v->GetJsonName().empty() ? v->GetName() : v->GetJsonName();

            if (v->GetType() == "array")
            {
                ofs << nsi << CODE_INDENTATION << CODE_INDENTATION << jsonName <<
                    " = new();" << std::endl;
                continue;
            }

            auto iter = TYPES_MAP.find(v->GetType());
            if (iter == TYPES_MAP.end()) continue;

            if (v->GetType() == "string")
            {
                ofs << nsi << CODE_INDENTATION << CODE_INDENTATION << jsonName <<
                    " = " << GetImportValue(v->GetDefault(), true) << ";" << std::endl;
            }
            else if (!v->GetDefault().empty())
            {
                ofs << nsi << CODE_INDENTATION << CODE_INDENTATION << jsonName <<
                    " = " << GetImportValue(v->GetDefault(), false, iter->second, jsonName) << ";" << std::endl;
            }
        }

        ofs << nsi << CODE_INDENTATION << "}" << std::endl;
    }

    // 命名空间
    void CSharpGenerator::GenerateNamespace(std::ofstream& ofs)
    {
        std::string ns = GetNameSpace();
        if (!ns.empty()) ofs << "namespace " << ns << std::endl << "{" << std::endl;
    }

    // 返回数据类型
    std::string CSharpGenerator::GetClassType(const std::string& ftype)
    {
        auto iter = TYPES_MAP.find(ftype);
        if (iter != TYPES_MAP.end()) return iter->second;
        return GetImportValue(ftype, false, "");
    }

    std::string CSharpGenerator::GetConstFile()
    {
        return GetPascalName(TrimRight(GetFileName(m_sSrcFile), ".pp"), false);
    }

    std::string CSharpGenerator::GetPascalName(const std::string& name, bool package)
    {
        std::stringstream result;
        int j = 0;
        for (size_t i = 0; i < name.length(); i++)
        {
            char ch = j == 0 ? std::toupper(name.at(i)) : std::tolower(name.at(i));
            if (ch >= 'a' && ch <= 'z')
            {
                result << ch;
                j = 1;
            }
            else if ((ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9'))
            {
                result << ch;
                j = 1;
            }
            else
            {
                if (package && ch == '.') result << ch;
                j = 0;
            }
        }
        return result.str();
    }

    // 返回类成员定义
    std::string CSharpGenerator::GetClassAttribute(const std::string& ftype, const std::string& subtype, const std::string& name)
    {
        if (ftype == "array")
        {
            auto iter = TYPES_MAP.find(subtype);
            if (iter != TYPES_MAP.end()) return "List<" + iter->second + "> " + name;
            // 枚举类型
            auto eiter = m_oEnumList.find(ftype);
            if (eiter != m_oEnumList.end()) return "List<" + *eiter + "> " + name;
            // 其他类型
            return "List<" + GetImportValue(subtype, false, "") + "> " + name;
        }
        // 其他类型
        auto iter = TYPES_MAP.find(ftype);
        if (iter != TYPES_MAP.end())
        {
            return iter->second + " " + name;
        }
        // 枚举类型
        auto eiter = m_oEnumList.find(ftype);
        if (eiter != m_oEnumList.end())
        {
            return *eiter + " " + name;
        }
        return GetImportValue(ftype, false, "") + "? " + name;
    }

    // 返回类成员定义
    std::string CSharpGenerator::GetJsonClassAttribute(const std::string& ftype, const std::string& subtype, const std::string& name)
    {
        if (ftype == "array")
        {
            auto iter = TYPES_MAP.find(subtype);
            if (iter != TYPES_MAP.end()) return "List<" + iter->second + "> " + name;
            return "List<" + GetImportValue(subtype, false, "") + "Json> " + name;
        }
        // 其他类型
        auto iter = TYPES_MAP.find(ftype);
        if (iter != TYPES_MAP.end())
        {
            return iter->second + " " + name;
        }
        // 枚举类型
        auto eiter = m_oEnumList.find(ftype);
        if (eiter != m_oEnumList.end())
        {
            return *eiter + " " + name;
        }
        return GetImportValue(ftype, false, "") + "Json? " + name;
    }

    // 从常量数据中返回
    std::string CSharpGenerator::GetImportValue(const std::string& constVal, bool bstring, const std::string& ftype,
        const std::string& attr)
    {
        auto iter = m_oConstMap.find(constVal);
        if (iter != m_oConstMap.end()) return ftype.empty() ? TrimImportValue(iter->second, attr) : "(" + ftype + ")" + TrimImportValue(iter->second, attr);
        return bstring ? "\"" + constVal + "\"" : constVal;
    }

    // 把包头去掉
    std::string CSharpGenerator::TrimImportValue(const std::string& val, const std::string& attr)
    {
        for (auto& v : m_oImports)
        {
            const std::string prefix = v + ".";
            if (val.find(prefix) == 0)
            {
                std::string simpleVal = TrimLeft(val, prefix);
                return attr.empty() || simpleVal.find(attr + ".") != 0 ? simpleVal : val;
            }
        }
        std::string simpleVal = TrimLeft(val, GetNameSpace() + ".");
        return attr.empty() || simpleVal.find(attr + ".") != 0 ? simpleVal : val;
    }
};
